package com.catazzz.springbootstudy.common.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * @作者: Tao
 * @日期: 2025/1/2
 * @时间: 15:43
 * @描述: 网络请求切面 <br><pre>
 *
 *      ＠Aspect注解，可以用来标识该类为一个AOP的切面
 */
@Slf4j
public class WebAspect {

    /**
     * 定义切点 <br><pre>
     *      ＠Pointcut用来定义切点；
     *          execution是用来匹配连接点的执行方法；
     *          public代表要匹配访问权限为public的方法；
     *          第一个*代表返回值为任意类型
     *          com.catazzz.springbootstudy.common.aop为包路径；
     *          第二个*代表前面包路径下的任意类；
     *          第三个*代表任意方法；
     *      （..）代表任意参数
     */
    @Pointcut("execution(public * com.catazzz.springbootstudy.common.aop.*.*(..))")
    public void pointCut() {

    }

    @Before(value = "pointCut()")
    public void before(JoinPoint joinPoint) {
        log.info("before");
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getName();
        Object[] args = joinPoint.getArgs();
        String[] parameterNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        Map<String, Object> paramMap = new HashMap<>();
        for (int i = 0; i < args.length; i++) {
            paramMap.put(parameterNames[i], args[i]);
        }

        log.info("path: {}", request.getServletPath());
        log.info("method name: {}", methodName);
        log.info("class name: {}", className);
        log.info("args: {}", paramMap);
    }

    @After(value = "pointCut()")
    public void after(JoinPoint joinPoint) {
        log.info("{} after", joinPoint.getSignature().getName());
    }

    @AfterReturning(value = "pointCut()", returning = "returnVal")
    public void afterReturning(JoinPoint joinPoint, Object returnVal) {
        log.info("{} afterReturning, returnVal: {}", joinPoint.getSignature().getName(), returnVal);
    }

    @AfterThrowing(value = "pointCut()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Exception e) {
        log.info("{} afterThrowing, exception: {}", joinPoint.getSignature().getName(), e.getMessage());
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) {
        long startTime = System.currentTimeMillis();
        Object result = null;
        try {
            result = joinPoint.proceed();
        } catch (Throwable e) {
            log.error("around异常", e);
        }

        log.info("execute time --->{}ms", System.currentTimeMillis() - startTime);
        return result;
    }
}
